﻿using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;

namespace GogTasks.UserControls
{
    public partial class PanelFingerScrollExtender : Component
    {
        public delegate void PanEventHandler(object sender, PanEventArgs args);
        /// <summary>
        /// Surface is panned
        /// </summary>
        public event PanEventHandler Pan;
        /// <summary>
        /// Begin of pan or scroll
        /// </summary>
        public event MouseEventHandler Begin;

        public PanelFingerScrollExtender()
        {
            InitializeComponent();
        }

        public PanelFingerScrollExtender(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            this.Disposed += new EventHandler(PanelFingerScrollExtender_Disposed);
        }

        void PanelFingerScrollExtender_Disposed(object sender, EventArgs e)
        {
            if (_panel != null)
            {
                DestructPanel();
            }
        }
        public UserControl AttachedPanel
        {
            get
            {
                return _panel;
            }
            set
            {
                if (!(value is ScrollablePanel))
                    throw new ArgumentException("AttachedPanel must be a ScrollablePanel");
                _panel = (ScrollablePanel) value;
                InitPanel();
            }
        }

        private ScrollablePanel _panel;
        

        #region Business methods
        private void InitPanel()
        {
            _panel.ControlAdded += _panel_ControlAdded;
            _panel.ControlsClearing += _panel_ControlsClearing;
            _panel.MouseDown += Control_MouseDown;
            _panel.MouseMove += Control_MouseMove;
            _panel.MouseUp += Control_MouseUp;
            foreach (Control c in _panel.InnerControls) InitInnerControl(c);
        }

        private void InitInnerControl(Control control)
        {
            control.MouseDown += Control_MouseDown;
            control.MouseMove += Control_MouseMove;
            control.MouseUp += Control_MouseUp;
            // Recursive - init all controls inside the control
            foreach (Control innerControl in control.Controls)
            {
                InitInnerControl(innerControl);
            }
        }

        private void DestructPanel()
        {
            _panel.ControlAdded -= _panel_ControlAdded;
            _panel.ControlsClearing -= _panel_ControlsClearing;
            _panel.MouseDown -= Control_MouseDown;
            _panel.MouseMove -= Control_MouseMove;
            _panel.MouseUp -= Control_MouseUp;
            ClearControlEvents();
        }

        private void ClearControlEvents()
        {
            foreach (Control c in _panel.InnerControls)
            {
                c.MouseDown -= Control_MouseDown;
                c.MouseMove -= Control_MouseMove;
                c.MouseUp -= Control_MouseUp;
            }
        }

        private int start_y;
        private int pan_y;

        private Point TranslateCoords(Control control, MouseEventArgs e)
        {
            int x;
            int y;

            if (control == _panel)
            {
                x = e.X;
                y = e.Y;
            }
            else
            {
                x = e.X + control.Location.X + _panel.InnerPanel.Location.X;
                y = e.Y + control.Location.Y + _panel.InnerPanel.Location.Y;
            }
            return new Point(x, y);
        }

        void _panel_ControlsClearing(object sender, EventArgs e)
        {
            ClearControlEvents();
        }

        void _panel_ControlAdded(object sender, ControlEventArgs args)
        {
            InitInnerControl(args.Control);

        }

        void Control_MouseUp(object sender, MouseEventArgs e)
        {
        }

        void Control_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                // Drag
                Point abs_e = TranslateCoords((Control)sender, e);
                var panY = abs_e.Y - start_y;
                start_y = abs_e.Y;
                OnPan(new PanEventArgs(0, panY));
                //Debug.WriteLine("Dragging: SRC: "+e.Y+" ABS: " + abs_e.Y + " DIFF: "+panY+  " INNR: "+ _panel.InnerPanel.Location.Y +" - Type:" + sender.GetType() + " --CtrlY: " + ((Control)sender).Location.Y);
            }
        }

        void Control_MouseDown(object sender, MouseEventArgs e)
        {
            Point abs_e = TranslateCoords((Control) sender, e);
            var newE = new MouseEventArgs(e.Button, 1, abs_e.X, abs_e.Y, 0);
            start_y = abs_e.Y;
            OnBegin(newE);
        }

        private void OnBegin(MouseEventArgs e)
        {
            if (Begin != null) Begin.Invoke(this, e);
        }
        private void OnPan(PanEventArgs e)
        {
            if (Pan != null) Pan.Invoke(this, e);
        }
        #endregion
    }

    public class PanEventArgs
    {
        public int PanY { get; set; }
        public int PanX { get; set; }
        public PanEventArgs(int x, int y) 
        { 
            PanX = x;
            PanY = y; 
        }
    }
}
